import React, { useState, useEffect } from "react";
import { faPlus, faFileImport } from "@fortawesome/free-solid-svg-icons";
import { FileSearch, FileList, BottomBtn, TabList } from "./components";
import SimpleMDE from "react-simplemde-editor";
import { v4 as uuidv4 } from "uuid";
import { flattenArr, objToArr } from "./utils/helper";
import useIpcRender from "./hooks/useIpcRender";

import "./App.css";
import "bootstrap/dist/css/bootstrap.min.css";
import "easymde/dist/easymde.min.css";
import cfs from "./utils/cfs";

const { join, basename, dirname } = window.require("path");
const { app, dialog } = window.require("@electron/remote");
const documentsPath = `${app.getPath("documents")}/blog-doc`;

function App() {
  // hooks
  const [files, setFiles] = useState({});
  const [targetFiles, setTargetFiles] = useState([]);
  const [selectId, setSelectId] = useState("");
  const [tabListIds, setTabListIds] = useState([]);
  const [unSavedIds, setUnSavedIds] = useState([]);
  // get/set file store
  const storePath = join(documentsPath, "files.json");
  useEffect(() => {
    cfs.readFile(storePath).then((data) => {
      const defaultFiles = JSON.parse(data).files;
      setFiles(defaultFiles);
    });
  }, []);
  const setFileStore = (files) => {
    const filesObj = {
      files: objToArr(files).reduce((result, item) => {
        const { id, title, path } = item;
        result[id] = {
          id,
          title,
          path,
        };
        return result;
      }, {}),
    };
    cfs
      .writeFile(storePath, JSON.stringify(filesObj))
      .then((data) => {
        console.log(data);
      })
      .catch((err) => {
        console.error(err);
      });
  };
  // variable
  const tabList = tabListIds.map((id) => {
    return files[id];
  });
  const activeItem = files[selectId];
  const filesArr = objToArr(files);
  const filesListArr = targetFiles.length > 0 ? targetFiles : filesArr;
  const selectFile = files[selectId];
  // tab events/func
  const handleTabClick = (id) => {
    setSelectId(id);
  };
  const handleTabClose = (id) => {
    const newTabListIds = tabListIds.filter((c) => c !== id);
    setTabListIds(newTabListIds);
    if (selectId === id) {
      setSelectId("");
      if (newTabListIds.length > 0) {
        setSelectId(newTabListIds[newTabListIds.length - 1]);
      }
    }
  };
  const handleChangeMDE = (newValue) => {
    if (files[selectId].body !== newValue) {
      if (!unSavedIds.includes(selectId)) {
        setUnSavedIds([...unSavedIds, selectId]);
      }
      const modifiedFile = { ...files[selectId], body: newValue };
      setFiles({ ...files, [selectId]: modifiedFile });
    }
  };
  // doc list events/function
  const handleFileClick = (id) => {
    setSelectId(id);
    if (!tabListIds.includes(id)) {
      setTabListIds([...tabListIds, id]);
    }
    if (!files[id].isLoaded) {
      cfs.readFile(files[id].path).then((data) => {
        const newFile = { ...files[id], isLoaded: true, body: data };
        setFiles({ ...files, [id]: newFile });
      });
    }
  };
  const handleSearch = (keyword) => {
    const targetFiles = filesArr.filter((c) => c.title.includes(keyword));
    setTargetFiles(targetFiles);
  };
  const handleEditTitle = (id, newValue, isNew) => {
    let oldPath = files[id].path;
    let newPath = isNew
      ? join(documentsPath, `${newValue}.md`)
      : join(dirname(files[id].path), `${newValue}.md`);
    const modifiedFile = {
      ...files[id],
      title: newValue,
      path: newPath,
      isNew: false,
    };
    const newFiles = { ...files, [id]: modifiedFile };
    if (cfs.checkName(newPath)) {
      console.log(
        `${newValue}.md already exists, please change your doc name another.`
      );
      return;
    }
    if (isNew) {
      cfs
        .writeFile(newPath, "## This is a new markdown doc")
        .then(() => {
          setFiles(newFiles);
          setFileStore(newFiles);
        })
        .catch((err) => {
          console.error(err);
        });
    } else {
      cfs
        .rename(oldPath, newPath)
        .then(() => {
          setFiles(newFiles);
          setFileStore(newFiles);
        })
        .catch((err) => {
          console.log(err);
        });
    }
  };
  const handleDeleteFile = (id) => {
    const { [id]: value, ...afterDelete } = files;
    if (files[id].isNew) {
      setFiles(afterDelete);
    } else {
      const delPath = files[id].path;
      if (cfs.checkName(delPath)) {
        cfs.deleteFile(delPath);
        setFileStore(afterDelete);
        handleTabClose(id);
      }
    }
  };
  const handleSaveFile = () => {
    const ids = unSavedIds.filter((c) => c !== selectId);
    setUnSavedIds(ids);
    const content = activeItem.body;
    const savePath = activeItem.path;
    cfs
      .writeFile(savePath, content)
      .then((data) => {
        console.log(data);
      })
      .catch((err) => {
        console.log(err);
      });
  };
  // bottom button events
  const handleNewFile = () => {
    const newId = uuidv4();
    if (!filesArr.find((c) => c.isNew)) {
      setFiles({
        ...files,
        [newId]: {
          id: newId,
          title: "new title",
          body: "*this is an new markdown*",
          isNew: true,
        },
      });
    }
  };
  const hanldeImportFile = () => {
    console.log(dialog);
    dialog
      .showOpenDialog({
        title: "open your browserwindow",
        properties: ["openFile", "multiSelections"],
        filters: [
          {
            name: "Markdown Files",
            extensions: ["md"],
          },
        ],
      })
      .then((data) => {
        const filePaths = data.filePaths;
        console.log(filePaths);

        const filterImportFiles = filePaths.filter((c) => {
          const alreadyExistsFiles = Object.values(files).find(
            (d) => d.path === c
          );
          return !alreadyExistsFiles;
        });

        const importFilesArr = filterImportFiles.map((c) => {
          return {
            id: uuidv4(),
            title: basename(c, ".md"),
            path: c,
          };
        });

        const newFiles = { ...files, ...flattenArr(importFilesArr) };
        setFiles(newFiles);
        setFileStore(newFiles);

        if (importFilesArr.length > 0) {
          dialog.showMessageBox({
            type: "info",
            message: `成功导入了${importFilesArr.length}个文件`,
          });
        }
      });
  };
  // set menu callback
  useIpcRender({
    "create-new-file": handleNewFile,
    "save-edit-file": handleSaveFile,
    "import-file": hanldeImportFile,
  });
  return (
    <div className="container-fluid px-0">
      <div className="row no-gutters">
        <div className="col-3 left-panel bg-light">
          <FileSearch onSearch={handleSearch} />
          {filesArr.length > 0 ? (
            <FileList
              files={filesListArr}
              onFileClick={handleFileClick}
              onEditTitle={handleEditTitle}
              onFileDelete={handleDeleteFile}
            />
          ) : (
            <span className="no-page ml-5">Your page list</span>
          )}
          <div className="row no-gutters button-group">
            <div className="col">
              <BottomBtn
                title="新建"
                icon={faPlus}
                btnCls="btn-primary"
                onBtnClick={handleNewFile}
              />
            </div>
            <div className="col">
              <BottomBtn
                title="导入"
                icon={faFileImport}
                btnCls="btn-success"
                onBtnClick={hanldeImportFile}
              />
            </div>
          </div>
        </div>
        <div className="col-9 right-panel bg-light">
          <TabList
            files={tabList}
            selectId={selectId}
            unSaveList={unSavedIds}
            onTabClick={handleTabClick}
            onTabClose={handleTabClose}
          />
          {!selectId && (
            <div className="no-page">Manage your markdown doc here</div>
          )}
          {selectId && (
            <SimpleMDE
              key={selectFile && selectFile.id}
              value={selectFile && selectFile.body}
              onChange={(value) => {
                handleChangeMDE(value);
              }}
              options={{
                minHeight: "524px",
              }}
            />
          )}
        </div>
      </div>
    </div>
  );
}

export default App;
